package com.anita.member.service;

import com.anita.member.domain.service.ImageStorageService;
import com.anita.member.common.config.QiniuConfig;
import com.anita.member.common.UploadResult;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.*;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.storage.model.FileListing;
import com.qiniu.util.Auth;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 七牛云存储服务实现
 *
 * @author wuyunbin
 */
@Slf4j
@Service
@ConditionalOnClass(name = "com.qiniu.util.Auth")
@ConditionalOnProperty(name = "image.upload.type", havingValue = "qiniu")
public class QiniuStorageService implements ImageStorageService {

    @Resource
    private QiniuConfig qiniuConfig;

    /**
     * 上传图片
     * @param file 图片输入流
     * @return
     * @throws IOException
     */
    @Override
    public UploadResult upload(MultipartFile file) throws IOException {
        log.info("config: {}", qiniuConfig);
        // 获取file的地址
        String originalFilename = file.getOriginalFilename();
        //file扩展名 extendFileName
        if (!StringUtils.hasText(originalFilename)) {
            return UploadResult.failure("上传文件不能为空");
        }
        String extendFileName = originalFilename.substring(originalFilename.lastIndexOf("."));

        // 默认不指定key的情况下，以文件内容的hash值作为文件名 时间日期前缀
        LocalDate currentDate = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd/");
        // 构建新的文件名
        String newFileName = currentDate.format(formatter) + UUID.randomUUID().toString().replace("-", "") + extendFileName;
        log.info("file: {}", originalFilename);

        // 构造一个带指定 Region 对象的配置类 - 使用autoRegion自动选择合适的区域
        Configuration cfg = new Configuration(Region.autoRegion());

        // 从 MultipartFile 直接获取输入流，避免先保存到本地再上传
        InputStream inputStream = file.getInputStream();

        Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
        String upToken = auth.uploadToken(qiniuConfig.getBucketName());
        log.info("upToken:{}", upToken);

        try (InputStream ignored = inputStream) {
            UploadManager uploadManager = new UploadManager(cfg);
            Response response = uploadManager.put(inputStream, newFileName, upToken, null, null);
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            String url = "";

            // 检查privateBucket是否为true，如果为null则默认为false
            if (Boolean.TRUE.equals(qiniuConfig.getPrivateBucket())) {
                // 使用token下载
                log.info("key:{}", newFileName);
                log.info("putRet.key:{}", putRet.key);
                url = downloadByToken(newFileName);
                log.info("URL：{}", url);
            } else {
                // 确保domain以"/"结尾
                String domain = qiniuConfig.getDomain();
                if (!domain.endsWith("/")) {
                    domain = domain + "/";
                }
                url = domain + putRet.key;
            }

            return UploadResult.success(newFileName, url, file.getSize());
        } catch (IOException ex) {
            log.error("Failed to upload file: {}", originalFilename, ex);
            return null;
        }
    }

    /**
     * 删除文件
     * @param fileName 文件名
     * @return
     */
    @Override
    public boolean delete(String fileName) {
        log.info("QiniuStorageService.delete: {}", fileName);
        
        // 检查fileName是否为空
        if (!StringUtils.hasText(fileName)) {
            log.warn("文件名为空，无法删除");
            return false;
        }
        
        try {
            // 构造一个带指定Region对象的配置类
            Configuration cfg = new Configuration(Region.autoRegion());
            
            // 获取认证信息
            Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
            
            // 创建BucketManager对象
            BucketManager bucketManager = new BucketManager(auth, cfg);
            
            // 调用delete方法删除文件
            bucketManager.delete(qiniuConfig.getBucketName(), fileName);
            
            log.info("文件删除成功: {}", fileName);
            return true;
        } catch (QiniuException e) {
            log.error("文件删除失败: {}, 错误码: {}, 错误信息: {}", 
                    fileName, e.code(), e.response != null ? e.response.toString() : e.getMessage());
            return false;
        }
    }

    /**
     * 获取文件的URL
     * @param fileName 文件名
     * @return
     */
    @Override
    public String getUrl(String fileName) {
        log.info("QiniuStorageService.getUrl: {}", fileName);
        
        // 检查fileName是否为空
        if (!StringUtils.hasText(fileName)) {
            log.warn("文件名为空，无法获取URL");
            return "";
        }
        
        // 检查privateBucket是否为true，如果为null则默认为false
        if (Boolean.TRUE.equals(qiniuConfig.getPrivateBucket())) {
            // 私有空间，需要生成带token的下载链接
            return downloadByToken(fileName);
        } else {
            // 公开空间，直接拼接URL
            String domain = qiniuConfig.getDomain();
            if (!domain.endsWith("/")) {
                domain = domain + "/";
            }
            return domain + fileName;
        }
    }

    /**
     * 根据token下载文件
     * @param fileName
     * @return
     */
    public String downloadByToken(String fileName) {
        String urlString = "";
        try {
            // 如果useHttps为null，默认为false
            Boolean useHttps = qiniuConfig.getUseHttps();
            DownloadUrl url = new DownloadUrl(qiniuConfig.getDomain(), useHttps != null ? useHttps : false, fileName);
            
            // 如果expires为null，默认为3600秒（1小时）
            Long expires = qiniuConfig.getExpires();
            long deadline = System.currentTimeMillis() / 1000 + (expires != null ? expires : 3600);
            
            Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
            urlString = url.buildURL(auth, deadline);
            log.info("urlString:{}", urlString);
        } catch (QiniuException e) {
            log.error("Failed to generate download URL: {}", e.getMessage());
            e.printStackTrace();
        }
        return urlString;
    }

    /**
     * 列举文件
     * @param prefix 文件名前缀
     * @param maxKeys 最大返回数量
     * @return
     */
    @Override
    public List<com.anita.member.common.FileInfo> listFiles(String prefix, int maxKeys) {
        log.info("QiniuStorageService.listFiles: prefix={}, maxKeys={}", prefix, maxKeys);
        
        List<com.anita.member.common.FileInfo> result = new ArrayList<>();
        
        try {
            Configuration cfg = new Configuration(Region.autoRegion());
            Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
            BucketManager bucketManager = new BucketManager(auth, cfg);
            
            // 列举文件
            FileListing fileListing = bucketManager.listFiles(qiniuConfig.getBucketName(), prefix, null, maxKeys, null);
            
            if (fileListing.items != null) {
                for (FileInfo qiniuFileInfo : fileListing.items) {
                    com.anita.member.common.FileInfo fileInfo = new com.anita.member.common.FileInfo();
                    fileInfo.setFileName(qiniuFileInfo.key);
                    fileInfo.setFileSize(qiniuFileInfo.fsize);
                    fileInfo.setContentType(qiniuFileInfo.mimeType);
                    fileInfo.setEtag(qiniuFileInfo.hash);
                    
                    // 转换时间戳为LocalDateTime
                    if (qiniuFileInfo.putTime != 0) {
                        Date date = new Date(qiniuFileInfo.putTime / 10000); // 七牛时间戳是纳秒，需要除以10000转为毫秒
                        fileInfo.setCreateTime(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()));
                    }
                    
                    fileInfo.setUrl(getUrl(qiniuFileInfo.key));
                    fileInfo.setExists(true);
                    
                    result.add(fileInfo);
                }
            }
            
            log.info("列举文件成功，共{}个文件", result.size());
            return result;
        } catch (QiniuException e) {
            log.error("列举文件失败: prefix={}, 错误码: {}, 错误信息: {}", 
                    prefix, e.code(), e.response != null ? e.response.toString() : e.getMessage());
            return result;
        }
    }

    /**
     * 获取文件信息
     * @param fileName 文件名
     * @return
     */
    @Override
    public com.anita.member.common.FileInfo getFileInfo(String fileName) {
        log.info("QiniuStorageService.getFileInfo: {}", fileName);
        
        if (!StringUtils.hasText(fileName)) {
            log.warn("文件名为空，无法获取文件信息");
            return com.anita.member.common.FileInfo.notExists(fileName);
        }
        
        try {
            Configuration cfg = new Configuration(Region.autoRegion());
            Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
            BucketManager bucketManager = new BucketManager(auth, cfg);
            
            // 获取文件信息
            FileInfo qiniuFileInfo = bucketManager.stat(qiniuConfig.getBucketName(), fileName);
            
            com.anita.member.common.FileInfo fileInfo = new com.anita.member.common.FileInfo();
            fileInfo.setFileName(fileName);
            fileInfo.setFileSize(qiniuFileInfo.fsize);
            fileInfo.setContentType(qiniuFileInfo.mimeType);
            fileInfo.setEtag(qiniuFileInfo.hash);
            
            // 转换时间戳为LocalDateTime
            if (qiniuFileInfo.putTime != 0) {
                Date date = new Date(qiniuFileInfo.putTime / 10000);
                fileInfo.setCreateTime(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()));
            }
            
            fileInfo.setUrl(getUrl(fileName));
            fileInfo.setExists(true);
            
            log.info("获取文件信息成功: {}", fileName);
            return fileInfo;
        } catch (QiniuException e) {
            if (e.code() == 612) {
                // 文件不存在
                log.info("文件不存在: {}", fileName);
                return com.anita.member.common.FileInfo.notExists(fileName);
            }
            log.error("获取文件信息失败: {}, 错误码: {}, 错误信息: {}", 
                    fileName, e.code(), e.response != null ? e.response.toString() : e.getMessage());
            return com.anita.member.common.FileInfo.notExists(fileName);
        }
    }

    /**
     * 检查文件是否存在
     * @param fileName 文件名
     * @return
     */
    @Override
    public boolean exists(String fileName) {
        log.info("QiniuStorageService.exists: {}", fileName);
        
        if (!StringUtils.hasText(fileName)) {
            log.warn("文件名为空，无法检查文件是否存在");
            return false;
        }
        
        try {
            Configuration cfg = new Configuration(Region.autoRegion());
            Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
            BucketManager bucketManager = new BucketManager(auth, cfg);
            
            // 获取文件信息来判断是否存在
            bucketManager.stat(qiniuConfig.getBucketName(), fileName);
            
            log.info("文件存在: {}", fileName);
            return true;
        } catch (QiniuException e) {
            if (e.code() == 612) {
                // 文件不存在
                log.info("文件不存在: {}", fileName);
                return false;
            }
            log.error("检查文件是否存在失败: {}, 错误码: {}, 错误信息: {}", 
                    fileName, e.code(), e.response != null ? e.response.toString() : e.getMessage());
            return false;
        }
    }

    /**
     * 批量删除文件
     * @param fileNames 文件名列表
     * @return
     */
    @Override
    public List<Boolean> batchDelete(List<String> fileNames) {
        log.info("QiniuStorageService.batchDelete: {}", fileNames);
        
        List<Boolean> results = new ArrayList<>();
        
        if (fileNames == null || fileNames.isEmpty()) {
            log.warn("文件名列表为空，无法批量删除");
            return results;
        }
        
        try {
            Configuration cfg = new Configuration(Region.autoRegion());
            Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
            BucketManager bucketManager = new BucketManager(auth, cfg);
            
            // 构建批量删除操作
            BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
            for (String fileName : fileNames) {
                batchOperations.addDeleteOp(qiniuConfig.getBucketName(), fileName);
            }
            
            // 执行批量删除
            Response response = bucketManager.batch(batchOperations);
            
            // 解析批量操作结果
            String[] batchResults = response.bodyString().split("\n");
            for (int i = 0; i < fileNames.size() && i < batchResults.length; i++) {
                // 七牛批量操作返回200表示成功
                boolean success = batchResults[i].contains("\"code\":200");
                results.add(success);
                
                if (success) {
                    log.info("批量删除成功: {}", fileNames.get(i));
                } else {
                    log.warn("批量删除失败: {}, 结果: {}", fileNames.get(i), batchResults[i]);
                }
            }
            
            return results;
        } catch (QiniuException e) {
            log.error("批量删除失败, 错误码: {}, 错误信息: {}", 
                    e.code(), e.response != null ? e.response.toString() : e.getMessage());
            
            // 如果批量操作失败，返回全部失败的结果
            for (int i = 0; i < fileNames.size(); i++) {
                results.add(false);
            }
            return results;
        }
    }

    /**
     * 生成预签名上传URL
     * @param fileName 文件名
     * @param expiration 过期时间（秒）
     * @return
     */
    @Override
    public String generatePresignedUploadUrl(String fileName, long expiration) {
        log.info("QiniuStorageService.generatePresignedUploadUrl: fileName={}, expiration={}", fileName, expiration);
        
        if (!StringUtils.hasText(fileName)) {
            log.warn("文件名为空，无法生成预签名上传URL");
            return "";
        }
        
        try {
            Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
            
            // 生成上传凭证，设置过期时间
            String upToken = auth.uploadToken(qiniuConfig.getBucketName(), fileName, expiration, null);
            
            log.info("生成预签名上传URL成功: {}", fileName);
            // 七牛云的上传是通过token进行的，这里返回token
            return upToken;
        } catch (Exception e) {
            log.error("生成预签名上传URL失败: {}, 错误信息: {}", fileName, e.getMessage());
            return "";
        }
    }

    /**
     * 生成预签名下载URL
     * @param fileName 文件名
     * @param expiration 过期时间（秒）
     * @return
     */
    @Override
    public String generatePresignedDownloadUrl(String fileName, long expiration) {
        log.info("QiniuStorageService.generatePresignedDownloadUrl: fileName={}, expiration={}", fileName, expiration);
        
        if (!StringUtils.hasText(fileName)) {
            log.warn("文件名为空，无法生成预签名下载URL");
            return "";
        }
        
        try {
            // 如果是私有空间，生成带token的下载链接
            if (Boolean.TRUE.equals(qiniuConfig.getPrivateBucket())) {
                Boolean useHttps = qiniuConfig.getUseHttps();
                DownloadUrl url = new DownloadUrl(qiniuConfig.getDomain(), useHttps != null ? useHttps : false, fileName);
                
                long deadline = System.currentTimeMillis() / 1000 + expiration;
                
                Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
                String downloadUrl = url.buildURL(auth, deadline);
                
                log.info("生成预签名下载URL成功: {}", fileName);
                return downloadUrl;
            } else {
                // 公开空间，直接返回公开URL
                String publicUrl = getUrl(fileName);
                log.info("生成公开下载URL: {}", fileName);
                return publicUrl;
            }
        } catch (QiniuException e) {
            log.error("生成预签名下载URL失败: {}, 错误信息: {}", fileName, e.getMessage());
            return "";
        }
    }

    /**
     * 复制文件
     * @param sourceFileName 源文件名
     * @param targetFileName 目标文件名
     * @return
     */
    @Override
    public boolean copyFile(String sourceFileName, String targetFileName) {
        log.info("QiniuStorageService.copyFile: source={}, target={}", sourceFileName, targetFileName);
        
        if (!StringUtils.hasText(sourceFileName) || !StringUtils.hasText(targetFileName)) {
            log.warn("源文件名或目标文件名为空，无法复制文件");
            return false;
        }
        
        try {
            Configuration cfg = new Configuration(Region.autoRegion());
            Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
            BucketManager bucketManager = new BucketManager(auth, cfg);
            
            // 复制文件
            bucketManager.copy(qiniuConfig.getBucketName(), sourceFileName, 
                             qiniuConfig.getBucketName(), targetFileName);
            
            log.info("文件复制成功: {} -> {}", sourceFileName, targetFileName);
            return true;
        } catch (QiniuException e) {
            log.error("文件复制失败: {} -> {}, 错误码: {}, 错误信息: {}", 
                    sourceFileName, targetFileName, e.code(), 
                    e.response != null ? e.response.toString() : e.getMessage());
            return false;
        }
    }

    /**
     * 移动文件
     * @param sourceFileName 源文件名
     * @param targetFileName 目标文件名
     * @return
     */
    @Override
    public boolean moveFile(String sourceFileName, String targetFileName) {
        log.info("QiniuStorageService.moveFile: source={}, target={}", sourceFileName, targetFileName);
        
        if (!StringUtils.hasText(sourceFileName) || !StringUtils.hasText(targetFileName)) {
            log.warn("源文件名或目标文件名为空，无法移动文件");
            return false;
        }
        
        try {
            Configuration cfg = new Configuration(Region.autoRegion());
            Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
            BucketManager bucketManager = new BucketManager(auth, cfg);
            
            // 移动文件
            bucketManager.move(qiniuConfig.getBucketName(), sourceFileName, 
                             qiniuConfig.getBucketName(), targetFileName);
            
            log.info("文件移动成功: {} -> {}", sourceFileName, targetFileName);
            return true;
        } catch (QiniuException e) {
            log.error("文件移动失败: {} -> {}, 错误码: {}, 错误信息: {}", 
                    sourceFileName, targetFileName, e.code(), 
                    e.response != null ? e.response.toString() : e.getMessage());
            return false;
        }
    }
}